package org.minuframework.net;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.Map.Entry;

import org.json.JSONObject;
import org.minuframework.json.JsonUtils;
import org.minuframework.lang.StringUtils;

/**
 * @Description http通信
 * @author      minu
 * @date        2018/05/01 18:22:65
 */
public class HttpUtils {
    
    // ------------------------------------------------------------------------
    // ************************************************************************
    // constants
    
    public static final String UTF8 = "utf-8";
    
    // ------------------------------------------------------------------------
    
    // ************************************************************************
    // public methods
    
    // ------------------------------------------------------------------------
    
    /**
     * HTTP GET请求
     * @param  spec    请求地址 String
     * @param  charset 请求编码 String
     * @param  timeout 超时时间 int
     * @return         远程资源的响应结果 String
     */
    public static String sendGet(String spec, String charset, int timeout) {
        InputStreamReader in = null;
        BufferedReader reader = null;
        StringBuilder result = new StringBuilder();
        
        try {
            // 请求的webservice的url
            URL url = new URL(spec);
            // 创建http链接
            HttpURLConnection http = (HttpURLConnection) url.openConnection();
            // 设置请求的方法类型
            http.setRequestMethod(RequestMethod.GET.name());
            
            // 设置通用的请求属性 设置请求格式
            http.setRequestProperty("accept", "*/*");
            http.setRequestProperty("connection", "Keep-Alive");
            http.setRequestProperty("user-agent", "Mozilla/4.0 (compatible;MSIE 6.0; Windows NT 5.1;SV1)");
            
            // 设置超时时间
            http.setConnectTimeout(timeout);
            http.setReadTimeout(timeout);
            
            // 建立连接
            http.connect();
            
            String read;
            in = new InputStreamReader(http.getInputStream(), charset);
            reader = new BufferedReader(in);
            while ((read = reader.readLine()) != null) {
                result.append(read);
            }
        } catch (IOException e) {
            e.printStackTrace();
            result.append(e.getMessage());
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
                result.append(e.getMessage());
            }
        }
        
        return result.toString();
    }
    
    /**
     * HTTP POST请求
     * @param  spec    请求地址 String
     * @param  params  参数 Map<String, Object>
     * @param  charset 请求编码 String
     * @param  timeout 超时时间 int
     * @return         远程资源的响应结果 String
     */
    public static String sendPost(String spec, Map<String, Object> params, String charset, int timeout) {
        OutputStreamWriter out = null;
        BufferedReader reader = null;
        StringBuilder result = new StringBuilder();
        
        try {
            // 请求的webservice的url
            URL url = new URL(spec);
            // 创建http链接
            HttpURLConnection http = (HttpURLConnection) url.openConnection();
            // 设置请求的方法类型
            http.setRequestMethod(RequestMethod.POST.name());
            
            // 设置通用的请求属性 设置请求格式
            http.setRequestProperty("accept", "*/*");
            http.setRequestProperty("connection", "Keep-Alive");
            http.setRequestProperty("user-agent", "Mozilla/4.0 (compatible;MSIE 6.0; Windows NT 5.1;SV1)");
            http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            
            // 设置超时时间
            http.setConnectTimeout(timeout);
            http.setReadTimeout(timeout);
            
            // 发送POST请求必须设置如下两行
            http.setDoInput(true);
            http.setDoOutput(true);
            // 建立连接
            http.connect();
            
            // 获取URLConnection对象对应的输出流
            out = new OutputStreamWriter(http.getOutputStream(), charset);
            if (params != null) {
                String param = buildUrl(params);
                out.write(param);
            }
            out.flush();
            
            String read;
            // 定义BufferedReader输入流来读取URL的响应
            reader = new BufferedReader(new InputStreamReader(http.getInputStream(), charset));
            while ((read = reader.readLine()) != null) {
                result.append(read);
            }
        } catch (IOException e) {
            e.printStackTrace();
            result.append(e.getMessage());
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
                result.append(e.getMessage());
            }
        }
        
        return result.toString();
    }
    
    // ------------------------------------------------------------------------
    
    /**
     * HTTP请求
     * @param  spec    请求地址 String
     * @param  method  请求方式 String
     * @param  charset 请求编码 String
     * @param  timeout 超时时间 int
     * @return         远程资源的响应结果 String
     */
    public static String sendHttp(String spec, RequestMethod method, String charset, int timeout) {
        StringBuilder result = new StringBuilder();
        if (method == RequestMethod.GET) {
            result.append(sendGet(spec, charset, timeout));
        } else if (method == RequestMethod.POST) {
            result.append(sendPost(spec, null, charset, timeout));
        }
        return result.toString();
    }
    
    /**
     * HTTP请求
     * @param  spec    请求地址 String
     * @param  method  请求方式 String
     * @param  charset 请求编码 String
     * @param  timeout 超时时间 int
     * @return         远程资源的响应结果 String
     */
    public static JSONObject sendHttpWithJSON(String spec, RequestMethod method, String charset, int timeout) {
        String result = sendHttp(spec, method, charset, timeout);
        if (StringUtils.isNotEmpty(result)) { return JsonUtils.toJSONObjectSafe(result); }
        return null;
    }
    
    /**
     * HTTP请求
     * @param  spec    请求地址 String
     * @param  params  参数 Map<String, Object>
     * @param  method  请求方式 String
     * @param  charset 请求编码 String
     * @param  timeout 超时时间 int
     * @return         远程资源的响应结果 String
     */
    public static String sendHttp(String spec, Map<String, Object> params, RequestMethod method, String charset, int timeout) {
        StringBuilder result = new StringBuilder();
        if (method == RequestMethod.GET) {
            spec += buildUrl(params, method);
            result.append(sendGet(spec, charset, timeout));
        } else if (method == RequestMethod.POST) {
            result.append(sendPost(spec, params, charset, timeout));
        }
        return result.toString();
    }
    
    /**
     * HTTP请求
     * @param  spec    请求地址 String
     * @param  params  参数 Map<String, Object>
     * @param  method  请求方式 String
     * @param  charset 请求编码 String
     * @param  timeout 超时时间 int
     * @return         远程资源的响应结果 String
     */
    public static JSONObject sendHttpWithJSON(String spec, Map<String, Object> params, RequestMethod method, String charset, int timeout) {
        String result = sendHttp(spec, params, method, charset, timeout);
        if (StringUtils.isNotEmpty(result)) { return JsonUtils.toJSONObjectSafe(result); }
        return null;
    }
    
    // ------------------------------------------------------------------------
    
    /**
     * HTTP请求
     * @param  spec    请求地址 String
     * @param  method  请求方式 String
     * @param  charset 请求编码 String
     * @return         远程资源的响应结果 String
     */
    public static String sendHttp(String spec, RequestMethod method, String charset) {
        StringBuilder result = new StringBuilder();
        if (method == RequestMethod.GET) {
            result.append(sendGet(spec, charset, 20 * 1000));
        } else if (method == RequestMethod.POST) {
            result.append(sendPost(spec, null, charset, 20 * 1000));
        }
        return result.toString();
    }
    
    /**
     * HTTP请求
     * @param  spec    请求地址 String
     * @param  method  请求方式 String
     * @param  charset 请求编码 String
     * @return         远程资源的响应结果 String
     */
    public static JSONObject sendHttpWithJSON(String spec, RequestMethod method, String charset) {
        String result = sendHttp(spec, method, charset);
        if (StringUtils.isNotEmpty(result)) { return JsonUtils.toJSONObjectSafe(result); }
        return null;
    }
    
    /**
     * HTTP请求
     * @param  spec    请求地址 String
     * @param  params  参数 Map<String, Object>
     * @param  method  请求方式 String
     * @param  charset 请求编码 String
     * @return         远程资源的响应结果 String
     */
    public static String sendHttp(String spec, Map<String, Object> params, RequestMethod method, String charset) {
        StringBuilder result = new StringBuilder();
        if (method == RequestMethod.GET) {
            spec += buildUrl(params, method);
            result.append(sendGet(spec, charset, 20 * 1000));
        } else if (method == RequestMethod.POST) {
            result.append(sendPost(spec, params, charset, 20 * 1000));
        }
        return result.toString();
    }
    
    /**
     * HTTP请求
     * @param  spec    请求地址 String
     * @param  params  参数 Map<String, Object>
     * @param  method  请求方式 String
     * @param  charset 请求编码 String
     * @return         远程资源的响应结果 String
     */
    public static JSONObject sendHttpWithJSON(String spec, Map<String, Object> params, RequestMethod method, String charset) {
        String result = sendHttp(spec, params, method, charset);
        if (StringUtils.isNotEmpty(result)) { return JsonUtils.toJSONObjectSafe(result); }
        return null;
    }
    
    // ------------------------------------------------------------------------
    
    /**
     * HTTP请求
     * @param  spec   请求地址 String
     * @param  method 请求方式 String
     * @return        远程资源的响应结果 String
     */
    public static String sendHttp(String spec, RequestMethod method) {
        StringBuilder result = new StringBuilder();
        if (method == RequestMethod.GET) {
            result.append(sendGet(spec, UTF8, 20 * 1000));
        } else if (method == RequestMethod.POST) {
            result.append(sendPost(spec, null, UTF8, 20 * 1000));
        }
        return result.toString();
    }
    
    /**
     * HTTP请求
     * @param  spec   请求地址 String
     * @param  method 请求方式 String
     * @return        远程资源的响应结果 String
     */
    public static JSONObject sendHttpWithJSON(String spec, RequestMethod method) {
        String result = sendHttp(spec, method);
        if (StringUtils.isNotEmpty(result)) { return JsonUtils.toJSONObjectSafe(result); }
        return null;
    }
    
    /**
     * HTTP请求
     * @param  spec   请求地址 String
     * @param  params 参数 Map<String, Object>
     * @param  method 请求方式 String
     * @return        远程资源的响应结果 String
     */
    public static String sendHttp(String spec, Map<String, Object> params, RequestMethod method) {
        StringBuilder result = new StringBuilder();
        if (method == RequestMethod.GET) {
            spec += buildUrl(params, method);
            result.append(sendGet(spec, UTF8, 20 * 1000));
        } else if (method == RequestMethod.POST) {
            result.append(sendPost(spec, params, UTF8, 20 * 1000));
        }
        return result.toString();
    }
    
    /**
     * HTTP请求
     * @param  spec   请求地址 String
     * @param  params 参数 Map<String, Object>
     * @param  method 请求方式 String
     * @return        远程资源的响应结果 String
     */
    public static JSONObject sendHttpWithJSON(String spec, Map<String, Object> params, RequestMethod method) {
        String result = sendHttp(spec, params, method);
        if (StringUtils.isNotEmpty(result)) { return JsonUtils.toJSONObjectSafe(result); }
        return null;
    }
    
    // ------------------------------------------------------------------------
    
    public static String buildUrl(Map<String, Object> params) {
        StringBuilder param = new StringBuilder();
        if (params != null) {
            for (Entry<String, Object> entry : params.entrySet()) {
                if (param.length() > 0) {
                    param.append("&");
                }
                param.append(entry.getKey());
                param.append("=");
                param.append(entry.getValue());
            }
        }
        return param.toString();
    }
    
    public static String buildUrl(Map<String, Object> params, RequestMethod method) {
        StringBuilder param = new StringBuilder();
        if (params != null) {
            for (Entry<String, Object> entry : params.entrySet()) {
                if (param.length() == 0) {
                    if (method == RequestMethod.GET) {
                        param.append("?");
                    }
                } else if (param.length() > 0) {
                    param.append("&");
                }
                param.append(entry.getKey());
                param.append("=");
                param.append(entry.getValue());
            }
        }
        return param.toString();
    }
    
    // ------------------------------------------------------------------------
    // ************************************************************************
    // public classes
    
    /**
     * Unicode、中文转换
     * @author minu
     */
    public static class UnicodeDecoder {
        
        /**
         * 中文转Unicode
         * @param  gbString 中文字符串 String
         * @return          Unicode字符串 String
         */
        public static String gbEncoding(final String gbString) {
            StringBuffer result = new StringBuffer();
            
            char[] utfBytes = gbString.toCharArray();
            for (int byteIndex = 0; byteIndex < utfBytes.length; byteIndex++) {
                String hexB = Integer.toHexString(utfBytes[byteIndex]); // 转换为16进制整型字符串
                if (hexB.length() <= 2) {
                    hexB = "00" + hexB;
                }
                result.append("\\u" + hexB);
            }
            
            return result.toString();
        }
        
        /**
         * Unicode转中文
         * @param  dataStr Unicode字符串 String
         * @return         中文字符 String
         */
        public static String decodeUnicode(final String dataStr) {
            StringBuffer result = new StringBuffer();
            
            int start = 0, end = 0;
            while (start > -1) {
                end = dataStr.indexOf("\\u", start + 2);
                String charStr;
                if (end == -1) {
                    charStr = dataStr.substring(start + 2, dataStr.length());
                } else {
                    charStr = dataStr.substring(start + 2, end);
                }
                
                char letter = (char) Integer.parseInt(charStr, 16); // 16进制parse整形字符串。
                result.append(new Character(letter).toString());
                start = end;
            }
            
            return result.toString();
        }
    }
    
}
